package org.gocom.components.coframe.auth.login;




import java.io.UnsupportedEncodingException;

import com.eos.foundation.eoscommon.BusinessDictUtil;
import com.eos.system.annotation.Bizlet;
import com.novell.ldap.LDAPConnection;
import com.novell.ldap.LDAPEntry;
import com.novell.ldap.LDAPException;
import com.novell.ldap.LDAPSearchResults;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;

import com.novell.ldap.LDAPAttribute;
import com.novell.ldap.LDAPAttributeSet;
import com.novell.ldap.util.Base64;
import com.primeton.workflow.commons.logging.Logger;
import com.primeton.workflow.commons.logging.LoggerFactory;
import com.system.tools.EncryptionDecryption;

import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;

/**
 * AD域管理
 * @author PRIMETON
 *
 */
@Bizlet("setLocaleLanguage")
public class ADdomainService {
	private static final Logger logger = LoggerFactory.getLogger(ADdomainService.class);
	 private static String ldapHost = null;//域主机
	 private static int ldapPort ;	  //域连接端口
	 private static int SSLldapPort;//域SSL连接端口
	 private static int ldapVersion =LDAPConnection.LDAP_V3;
	 private static String loginDN = null;//管理员用户
	 private static String  loginDNPwd = null;////管理员密码	 
	 private static LDAPConnection conn =null;//管理员普通链接
	private static Hashtable<String, String> env = null;
	private static Control[] connCtls = null;	
	// private static String keystore = "C:\\key\\keys.keystore.jks"; //证书所在目录(证书库)  


	public static void main(String[] args) {
		
	//	init(null,0,0,null,"2911d905b29bdea2976d3d0deac04430");
		
		//测试服务器支持的版本
	//	Boolean res = getVersiom(LDAPConnection.LDAP_V3);
		
		//测试用户名是否存在
		String dn =userIsExist("yuzhikun");
		if(null != dn){
			logger.info("用户名存在域中，"+dn);
		}else{
			logger.info("用户名不存在域中！");
		}
		
		//测试用户账号和密码是否匹配
		Boolean userAuth = userAuth("yuzhikun","yuzhikun");
		if(userAuth){
			logger.info("用户验证通过！");
		}else{
			logger.info("用户验证失败！");
		}
		
		//更新密码
		Boolean isPassword =changPWD("yuzhikun","yuzhikun");
		if(isPassword){
			logger.info("密码修改成功！");
		}else{
			logger.info("密码修改失败！");
		}

	}
	
	/**
	 * 连接初始化,配置信息来源业务字典的（LDAP）
	 * @param ldapHost
	 * @param ldapPort
	 * @param SSLldapPort
	 * @param loginDN
	 * @param loginDNPwd
	 */
	@Bizlet("setLocaleLanguage")
	public static Boolean init(){  
		Boolean isInit = false;
		Boolean isChange= false;

		String ldapHost  = BusinessDictUtil.getDictName("LDAP","ldapHost");
		int  ldapPort = Integer.parseInt(BusinessDictUtil.getDictName("LDAP","ldapPort"));
		int  SSLldapPort = Integer.parseInt(BusinessDictUtil.getDictName("LDAP","SSLldapPort"));
		String loginDN = BusinessDictUtil.getDictName("LDAP","loginDN");
		String decryptTest = BusinessDictUtil.getDictName("LDAP","loginDNPwd");		
			try {
				decryptTest = EncryptionDecryption.decrypt(decryptTest);//解密
			} catch (Exception e) {
				e.printStackTrace();
				return false;
			}		    
		
		
		if( null != ldapHost && ! ldapHost.equalsIgnoreCase( ADdomainService.ldapHost )){
			ADdomainService.ldapHost = ldapHost;
			isChange= true;
		}
        if(ADdomainService.ldapPort !=  ldapPort){
        	ADdomainService.ldapPort =  ldapPort;
        	isChange= true;
        }
        if( SSLldapPort !=  ADdomainService.SSLldapPort){
        	ADdomainService.SSLldapPort =  SSLldapPort;
        	isChange= true;
        }
        if(null != loginDN && ! loginDN.equalsIgnoreCase( ADdomainService.loginDN)){
        	ADdomainService.loginDN = loginDN;
        	isChange= true;
        }
        
       
        if(null !=decryptTest && !decryptTest.equals(ADdomainService.loginDNPwd )){
        	ADdomainService.loginDNPwd = decryptTest;
        	isChange= true;
        }

        if(null != conn  && conn.isConnected()){
        	try {
				conn.disconnect();//业务字典变更就放弃之前的管理员连接
			} catch (LDAPException e) {
				e.printStackTrace();
			}
			conn=null;
		}	
		if(  ADdomainService.ldapHost != null && ADdomainService.ldapPort >=0  && ADdomainService.SSLldapPort >=0 && ADdomainService.loginDN != null && ADdomainService.loginDNPwd != null){
				isInit =true;
		}	
		return isInit;

	}
	
	
	/**
	 * 获取连接
	 * @return
	 */
	 public static LDAPConnection getConn(){
			 if((null ==conn  )){
				 conn = conn( ldapHost, ldapPort, loginDN, loginDNPwd );
			 }
			 if(null !=conn   && !conn.isBound()){
				 try {
					conn.bind(ldapVersion, loginDN, loginDNPwd.getBytes("UTF8"));
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				} catch (LDAPException e) {
					e.printStackTrace();
				}
			 }	 
		 return conn;	
	 }
	 
	 /**
	  * 获取安全连接
	  * @return
	  */
	 private static LdapContext  sslConnect() {
		 if(!init()){
			 logger.error("请到业务字典进行LDAP信息配置");
			 return null;
		 }
		  LdapContext ctx = null;
		 if(env == null ){
			 env = new Hashtable<String, String>();
				env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
				env.put(Context.PROVIDER_URL, "ldap://".concat(ldapHost).concat(":").concat(""+SSLldapPort));// LDAP server
				env.put(Context.SECURITY_PRINCIPAL, loginDN);
				env.put(Context.SECURITY_AUTHENTICATION, "simple");
				env.put(Context.SECURITY_CREDENTIALS, "$oa2AD11%");
				env.put(Context.SECURITY_PROTOCOL, "ssl");
				env.put("java.naming.ldap.factory.socket", "org.gocom.components.coframe.auth.login.DummySSLSocketFactory");
				// 此处若不指定用户名和密码,则自动转换为匿名登录							
		 }
		 try {
				ctx = new InitialLdapContext(env, connCtls);
			} catch (NamingException e) {
				e.printStackTrace();
			}
		 return ctx;
		}
	 
	 /**
	  * 关闭连接
	  * @param conn
	  */
	 public static void close(LDAPConnection conn){
		 if(conn.isConnected()){
			 try {
				conn.disconnect();
			} catch (LDAPException e) {
				e.printStackTrace();
			}
		 }
	 }	
	
	 /**
	  * 获取服务器支持的版本
	  * @param LDAPVersion
	  * @return
	  */
	@Bizlet("setLocaleLanguage")
	public static Boolean getVersiom(int LDAPVersion){
		LDAPConnection lc = getConn();
		if(lc.isConnectionAlive() && lc.isBound()){
			String searchBase = "";//搜索域	
			String searchFilter = "objectclass=*";	
			int searchScope = LDAPConnection.SCOPE_BASE;//查询范围： SCOPE_BASE、SCOPE_ONE、SCOPE_SUB、SCOPE_SUBORDINATESUBTREE
			LDAPSearchResults searchResults = null;
			try {
				searchResults = lc.search(searchBase,searchScope, searchFilter, null, false);
				while (searchResults.hasMore()) {
					LDAPEntry nextEntry = null;
					try {
						nextEntry = searchResults.next();
					} catch (LDAPException e) {
						if(null != nextEntry){
						  logger.error("ErrorCode: "+e.getResultCode()+" Error: " + e.toString());
						}					
						if (e.getResultCode() == LDAPException.LDAP_TIMEOUT|| e.getResultCode() == LDAPException.CONNECT_ERROR) {
							break;
						} else {
							continue;
						}
					}
					@SuppressWarnings("unused")
					String tempDN = nextEntry.getDN();
					//logger.info("DN =: " + tempDN);
					LDAPAttributeSet attributeSet = nextEntry.getAttributeSet();
					@SuppressWarnings("unchecked")
					Iterator<LDAPAttribute> allAttributes = attributeSet.iterator();
					while (allAttributes.hasNext()) {
						LDAPAttribute attribute = allAttributes.next();
						String attributeName = attribute.getName();
						@SuppressWarnings("unchecked")
						Enumeration<String> allValues = attribute.getStringValues();
						if (null == allValues) {
							continue;
						}
						while (allValues.hasMoreElements()) {
							String value = allValues.nextElement();							
							if("supportedLDAPVersion".equals(attributeName) && value.equals(LDAPVersion)){//作为server2008 用户名
								return true;
							}
							//logger.info("|---- ---- " + attributeName+ " = " + value);
						}
					}
				}
			} catch (LDAPException e) {
				logger.error("ErrorCode: "+e.getResultCode()+" Error: " + e.toString());
			}
		}
		return false;
				
	}
	
	/**
	 * 普通连接处理
	 * @param ldapHost
	 * @param ldapPort
	 * @param loginDN
	 * @param password
	 * @return 失败返回值为null
	 */
	public static LDAPConnection conn(String ldapHost,int ldapPort,String loginDN,String password ){	
		if(!init()){
			 logger.error("请到业务字典进行LDAP信息配置");
			 return null;
		 }
		LDAPConnection lc = new LDAPConnection();					
			try {
				ldapHost=BusinessDictUtil.getDictName("LDAP","ldapHost");
				lc.connect(ldapHost, ldapPort);
				lc.bind(ldapVersion, loginDN, password.getBytes("UTF8"));				
				logger.info("获取连接成功!");
			} catch (LDAPException e ) {
				logger.info("获取连接失败！",e);
				System.out.println(e.getMessage());
				try {//链接不到连备用IP
					ldapHost=BusinessDictUtil.getDictName("LDAP","ldapHost2");
					lc.connect(ldapHost, ldapPort);
					lc.bind(ldapVersion, loginDN, password.getBytes("UTF8"));				
					logger.info("获取连接成功!");
				} catch (LDAPException e1 ) {
					logger.info("获取连接失败！",e1);
					System.out.println(e.getMessage());
				} catch (UnsupportedEncodingException e1) {
					logger.info("获取连接失败！",e1);
					System.out.println(e.getMessage());
				}	
			} catch (UnsupportedEncodingException e) {
				logger.info("获取连接失败！",e);
				System.out.println(e.getMessage());
				try {
					ldapHost=BusinessDictUtil.getDictName("LDAP","ldapHost2");
					lc.connect(ldapHost, ldapPort);
					lc.bind(ldapVersion, loginDN, password.getBytes("UTF8"));				
					logger.info("获取连接成功!");
				} catch (LDAPException e1 ) {
					logger.info("获取连接失败！",e1);
					System.out.println(e.getMessage());
				} catch (UnsupportedEncodingException e1) {
					logger.info("获取连接失败！",e1);
					System.out.println(e.getMessage());
				}	
			}	
		return lc;					
	}
	


	
	/**
	 * 校验用户是否存在
	 * @param verifyUserName
	 * @return 失败返回值为null
	 */
	@SuppressWarnings("unchecked")
	@Bizlet("setLocaleLanguage")
	public static String userIsExist(String verifyUserName){
		String returnDN=null;
		LDAPConnection lc = getConn();
		if(lc.isBound()){
			String searchBase = loginDN.substring(loginDN.indexOf("DC="),loginDN.length());//搜索域	
			String searchFilter = "sAMAccountName="+verifyUserName;	
			int searchScope = LDAPConnection.SCOPE_SUB;//查询范围： SCOPE_BASE、SCOPE_ONE、SCOPE_SUB、SCOPE_SUBORDINATESUBTREE
			LDAPSearchResults searchResults;
			try {
				searchResults = lc.search(searchBase,searchScope, searchFilter, null, false);
				while (searchResults.hasMore()) {
					LDAPEntry nextEntry = null;
					try {
						nextEntry = searchResults.next();
					} catch (LDAPException e) {
						if(null != nextEntry){
						  logger.error("ErrorCode: "+e.getResultCode()+" Error: " + e.toString());
						}					
						if (e.getResultCode() == LDAPException.LDAP_TIMEOUT|| e.getResultCode() == LDAPException.CONNECT_ERROR) {
							break;
						} else {
							continue;
						}
					}
					String tempDN = nextEntry.getDN();
					//logger.info("DN =: " + tempDN);
					LDAPAttributeSet attributeSet = nextEntry.getAttributeSet();
					Iterator<LDAPAttribute> allAttributes = attributeSet.iterator();
					while (allAttributes.hasNext()) {
						LDAPAttribute attribute = allAttributes.next();
						//String attributeName = attribute.getName();
						Enumeration<String> allValues = attribute.getStringValues();
						if (null == allValues) {
							continue;
						}
						while (allValues.hasMoreElements()) {
							String value = allValues.nextElement();
							if (!Base64.isLDIFSafe(value)) {
								value = Base64.encode(value.getBytes());
							}
							if(value.equals(verifyUserName)){//作为server2008 用户名
								logger.info(verifyUserName+"存在【"+tempDN+"]");
								returnDN=nextEntry.getDN();
								return returnDN;
							}
							//logger.info("|---- ---- " + attributeName+ " = " + value);
						}
					}
				}
			} catch (LDAPException e) {
				logger.error("ErrorCode: "+e.getResultCode()+" Error: " + e.toString());
			}
		}
		return returnDN;
				
	}
	
  /**
   * 用户验证
   * @param userName
   * @param password
   * @return 失败返回值为false
   */
	@Bizlet("setLocaleLanguage")
	public static boolean userAuth(String userName,String password){
		 boolean authResult=false;
		 String dn = userIsExist( userName);
		 if(null !=dn){
			 LDAPConnection lc = conn( ldapHost, ldapPort, dn, password);
			 System.out.println(lc+".........."+lc.isConnectionAlive()+"........."+lc.isBound());
			 if(null !=lc && lc.isConnectionAlive()&& lc.isBound()){
				 authResult = true;				 
			 }
			 close(lc);
		 }
		 return authResult;
	}
	
	/**
	 * 重置用户密码
	 * @param userName
	 * @param newPassword 
	 * @return 
	 * @throws LDAPException
	 * @throws UnsupportedEncodingException
	 */
	@Bizlet("setLocaleLanguage")
	public static boolean changPWD(String username, String password) {
		boolean flage = false;
		LdapContext ctx = new ADdomainService().sslConnect();//SSL连接
		if(null == ctx){ return false;}
		String  userDn = userIsExist(username);//判断用户是否存在
		if(null != userDn){
			ModificationItem[] mods = new ModificationItem[1];		
			  try {
			   byte[] newUnicodePassword = ("\"" + password + "\"").getBytes("UTF-16LE");
			   mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("unicodePwd", newUnicodePassword));
			   ctx.modifyAttributes(userDn, mods);
			   logger.info("Finish reset password" + username);
			   flage = true;
			  } catch (UnsupportedEncodingException e ) {
			   logger.error("UnsupportedEncodingException " + e);
			  } catch (NamingException e) {
			   logger.error("NamingException: " + e);
			  }		  			 
		}else{
			logger.warn(username+"不存在域中！");
		}
		
		 try {
				ctx.close();
			} catch (NamingException e) {
				e.printStackTrace();
		}
		 return flage;
	}
}
